package com.echo.code.thread.latch.impl;

import static java.lang.System.currentTimeMillis;

import com.echo.code.thread.latch.Latch;
import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;

/**
 * CountDownLatch Created by baiyap on 2018/9/24.
 */
public class CountDownLatch extends Latch {

  private static final Logger LOGGER = Logger.getLogger(CountDownLatch.class.getName());

  public CountDownLatch(int limit) {
    super(limit);
  }

  @Override
  public void await() throws InterruptedException {
    synchronized (this) {
      while (limit > 0) {
        this.wait();
      }
    }
  }

  @Override
  public void await(long millis) throws InterruptedException, TimeoutException {
    if (millis <= 0) {
      await();
    }
    synchronized (this) {
      long remainingMillis = millis;
      long endMillis = currentTimeMillis() + remainingMillis;
      while (limit > 0) {
        if (remainingMillis <= 0) {
          throw new TimeoutException("Time over specify time.");
        }
        this.wait(remainingMillis);
        remainingMillis = endMillis - currentTimeMillis();
      }
    }
  }

  @Override
  public void countDown() {
    synchronized (this) {
      if (limit <= 0) {
        throw new RuntimeException("All of task have already done.");
      }
      limit--;
      LOGGER.info(getCurrentThreadName() + " done，undone count is " + limit);
      this.notifyAll();
    }
  }
}